package com.leha.forum.lehare.config;

import com.leha.forum.lehare.auth.AuthorizationFilter;
import com.leha.forum.lehare.auth.CustomLoginFilter;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * @author lovelycat
 * @version 1.0
 * @since 2025-04-15 21:32
 */
@Component
public class SecurityConfig {
    @Resource
    private AuthenticationConfiguration authenticationConfiguration;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // 以下接口不需要经过身份验证
        List<RequestMatcher> requestMatchers = new ArrayList<>();
        requestMatchers.add(new AntPathRequestMatcher("/login", HttpMethod.POST.name()));

        requestMatchers.add(new AntPathRequestMatcher("/carousel/all", HttpMethod.GET.name()));

        requestMatchers.add(new AntPathRequestMatcher("/category/all", HttpMethod.GET.name()));

        requestMatchers.add(new AntPathRequestMatcher("/post/list", HttpMethod.GET.name()));
        requestMatchers.add(new AntPathRequestMatcher("/post/listTop", HttpMethod.GET.name()));
        requestMatchers.add(new AntPathRequestMatcher("/post/listStar", HttpMethod.GET.name()));
        requestMatchers.add(new AntPathRequestMatcher("/post/listLatest", HttpMethod.GET.name()));
        requestMatchers.add(new AntPathRequestMatcher("/post/listHot", HttpMethod.GET.name()));
        requestMatchers.add(new AntPathRequestMatcher("/post/listByCat", HttpMethod.GET.name()));
        requestMatchers.add(new AntPathRequestMatcher("/post/increaseViewCount", HttpMethod.POST.name()));

        requestMatchers.add(new AntPathRequestMatcher("/comment/post", HttpMethod.POST.name()));

        requestMatchers.add(new AntPathRequestMatcher("/api/**", HttpMethod.GET.name()));
        requestMatchers.add(new AntPathRequestMatcher("/api/**", HttpMethod.POST.name()));
        requestMatchers.add(new AntPathRequestMatcher("/api/**", HttpMethod.DELETE.name()));
        requestMatchers.add(new AntPathRequestMatcher("/api/**", HttpMethod.PUT.name()));

        // 禁用 CSRF
        http.csrf(AbstractHttpConfigurer::disable);
        // 禁用跨域
        http.cors(AbstractHttpConfigurer::disable);

        // JWT 验证无需 Session
        http.sessionManagement(it -> it.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

        http.authorizeHttpRequests(registry -> {
            requestMatchers.forEach(e -> registry.requestMatchers(e).permitAll());
            registry.anyRequest().authenticated();
        });

        // 由自定义的登录验证过滤器接管验证逻辑并返回 jwt token
        http.addFilterBefore(
                new CustomLoginFilter("/login", authenticationConfiguration.getAuthenticationManager()),
                UsernamePasswordAuthenticationFilter.class
        );

        // 验证用户 Token 是否有效
        http.addFilterBefore(new AuthorizationFilter(requestMatchers), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        // 用户密码加密采用 BCrypt
        return new BCryptPasswordEncoder();
    }
}
